/**
 * @file FileIO.cpp
 * @brief 文件输入输出处理类的实现
 * 
 * 实现了高性能的文件读写功能，包括：
 * 1. 内存映射文件读取
 * 2. 大缓冲区写入优化
 * 3. UTF-16LE编码支持
 * 4. 跨平台实现
 */

#include "FileIO.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <iostream>
#include <locale>

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

/**
 * @brief 内存映射文件类构造函数
 * 
 * 初始化所有成员变量为空值或无效值:
 * - Windows平台: 文件句柄和映射句柄设为nullptr
 * - POSIX平台: 文件描述符设为-1,长度设为0
 * - 映射数据指针设为nullptr
 */
FileIO::MemoryMappedFile::MemoryMappedFile() :
#ifdef _WIN32
    hFile(nullptr), hMapping(nullptr),
#else
    fd(-1), length(0),
#endif
    data(nullptr)
{
}

/**
 * @brief 内存映射文件类析构函数
 */
FileIO::MemoryMappedFile::~MemoryMappedFile()
{
#ifdef _WIN32
    if (data)
        UnmapViewOfFile(data);
    if (hMapping)
        CloseHandle(hMapping);
    if (hFile)
        CloseHandle(hFile);
#else
    if (data != MAP_FAILED && data != nullptr)
        munmap(data, length);
    if (fd != -1)
        close(fd);
#endif
}

/**
 * @brief 打开并映射文件
 */
bool FileIO::MemoryMappedFile::open(const std::string &filename, size_t &fileSize)
{
#ifdef _WIN32
    hFile = CreateFileA(filename.c_str(),
                       GENERIC_READ,
                       FILE_SHARE_READ,
                       NULL,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return false;

    LARGE_INTEGER size;
    if (!GetFileSizeEx(hFile, &size))
    {
        CloseHandle(hFile);
        return false;
    }
    fileSize = size.QuadPart;

    hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (!hMapping)
    {
        CloseHandle(hFile);
        return false;
    }

    data = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
    if (!data)
    {
        CloseHandle(hMapping);
        CloseHandle(hFile);
        return false;
    }
#else
    fd = ::open(filename.c_str(), O_RDONLY);
    if (fd == -1)
        return false;

    struct stat sb;
    if (fstat(fd, &sb) == -1)
    {
        close(fd);
        return false;
    }
    fileSize = sb.st_size;
    length = fileSize;

    data = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
    if (data == MAP_FAILED)
    {
        close(fd);
        return false;
    }
#endif
    return true;
}

/**
 * @brief 获取映射的内存数据指针
 */
void *FileIO::MemoryMappedFile::getData() const
{
    return data;
}

/**
 * @brief 检查文件是否存在
 */
bool FileIO::checkFileExists(const std::string &filename)
{
    std::ifstream file(filename);
    if (!file)
    {
        throw std::runtime_error("文件不存在或无法访问: " + filename);
    }
    return true;
}

/**
 * @brief 读取已知节点数据
 * 
 * 使用内存映射方式高效读取大文件:
 * 1. 预分配足够大的向量空间(2M)避免频繁扩容
 * 2. 使用1MB大小的读取缓冲区优化IO性能
 * 3. 跳过文件头部的标题行
 * 4. 按行解析四个double值(x,y,z,s1)
 * 5. 使用emplace_back直接构造对象
 */
void FileIO::readKnownNodes(const std::string &filename,
                           std::vector<NodeProperty> &nodes)
{
    nodes.clear();
    nodes.reserve(2000000);

    size_t fileSize;
    MemoryMappedFile mmFile;

    if (!mmFile.open(filename, fileSize))
    {
        throw std::runtime_error("无法打开文件: " + filename);
    }

    try
    {
        const char *current = static_cast<const char *>(mmFile.getData());
        const char *end = current + fileSize;
        const size_t BUFFER_SIZE = 1024 * 1024;  // 1MB缓冲区
        char *buffer = new char[BUFFER_SIZE];
        size_t bufferPos = 0;

        // 跳过标题行
        while (current < end && *current != '\n') current++;
        if (current < end && *current == '\n') current++;

        NodeProperty node;
        while (current < end)
        {
            bufferPos = 0;
            while (current < end && *current != '\n' && bufferPos < BUFFER_SIZE - 1)
            {
                buffer[bufferPos++] = *current++;
            }
            buffer[bufferPos] = '\0';
            if (current < end && *current == '\n') current++;

            double x, y, z, s1;
            if (sscanf(buffer, "%lf %lf %lf %lf", &x, &y, &z, &s1) == 4)
            {
                node.point = Point3D(x, y, z);
                node.s1_value = s1;
                nodes.push_back(node);
            }
        }

        delete[] buffer;
    }
    catch (const std::exception &e)
    {
        throw std::runtime_error("处理文件时发生错误: " + std::string(e.what()));
    }
}

/**
 * @brief 读取未知节点数据
 * 
 * 使用内存映射方式高效读取大文件:
 * 1. 预分配足够大的向量空间(1M)避免频繁扩容
 * 2. 使用1MB大小的读取缓冲区优化IO性能
 * 3. 跳过文件头部的标题行
 * 4. 按行解析一个int和三个double值(index,x,y,z)
 * 5. 使用emplace_back直接构造Point3D对象
 */
void FileIO::readUnknownNodes(const std::string &filename,
                             std::vector<Point3D> &points)
{
    points.clear();
    points.reserve(1000000);

    size_t fileSize;
    MemoryMappedFile mmFile;

    if (!mmFile.open(filename, fileSize))
    {
        throw std::runtime_error("无法打开文件: " + filename);
    }

    try
    {
        const char *current = static_cast<const char *>(mmFile.getData());
        const char *end = current + fileSize;
        const size_t BUFFER_SIZE = 1024 * 1024;  // 1MB缓冲区
        char *buffer = new char[BUFFER_SIZE];
        size_t bufferPos = 0;

        // 跳过标题行
        while (current < end && *current != '\n') current++;
        if (current < end && *current == '\n') current++;

        while (current < end)
        {
            bufferPos = 0;
            while (current < end && *current != '\n' && bufferPos < BUFFER_SIZE - 1)
            {
                buffer[bufferPos++] = *current++;
            }
            buffer[bufferPos] = '\0';
            if (current < end && *current == '\n') current++;

            int index;
            double x, y, z;
            if (sscanf(buffer, "%d %lf %lf %lf", &index, &x, &y, &z) == 4)
            {
                points.emplace_back(x, y, z);
            }
        }

        delete[] buffer;
    }
    catch (const std::exception &e)
    {
        throw std::runtime_error("处理文件时发生错误: " + std::string(e.what()));
    }
}

/**
 * @brief 保存插值结果到文件
 * 
 * 使用二进制模式和大缓冲区优化写入性能:
 * 1. 使用二进制模式打开文件避免文本转换开销
 * 2. 设置8MB写入缓冲区减少系统调用次数
 * 3. 预分配字符串缓冲区避免频繁内存分配
 * 4. 批量写入结果减少IO操作次数
 * 5. 使用\t作为分隔符,\n作为行结束符
 */
void FileIO::saveResults(const std::string &filename,
                        const std::vector<Result> &results)
{
    std::ofstream file(filename, std::ios::binary);  // 使用二进制模式
    if (!file)
    {
        throw std::runtime_error("无法创建输出文件: " + filename);
    }

    // 设置大缓冲区
    const int BUFFER_SIZE = 8 * 1024 * 1024;  // 8MB缓冲区
    std::unique_ptr<char[]> buffer(new char[BUFFER_SIZE]);
    file.rdbuf()->pubsetbuf(buffer.get(), BUFFER_SIZE);

    // 写入标题行
    file << "No.\tx\ty\tz\tS1\n";

    // 预分配字符串缓冲区
    std::string line;
    line.reserve(128);

    // 批量写入结果
    for (const auto &result : results)
    {
        line.clear();
        line += std::to_string(result.index);
        line += '\t';
        line += std::to_string(static_cast<int>(result.point.x));
        line += '\t';
        line += std::to_string(static_cast<int>(result.point.y));
        line += '\t';
        line += std::to_string(static_cast<int>(result.point.z));
        line += '\t';
        
        char s1_str[32];
        snprintf(s1_str, sizeof(s1_str), "%.4f\n", result.s1_value);
        line += s1_str;
        
        file.write(line.c_str(), line.size());
    }

    file.flush();
} 